/**
 * WebSocket服务
 * 用于管理与后端的WebSocket连接和数据通信
 */
import { Client } from '@stomp/stompjs';
import SockJS from 'sockjs-client';
import { WS_URL, WS_CONFIG } from '../config/proxy';

class WebSocketService {
  constructor() {
    this.stompClient = null;
    this.connected = false;
    this.subscriptions = new Map();
    this.reconnectAttempts = 0;
    this.reconnectTimer = null;
    this.pingTimer = null;
  }

  /**
   * 连接到WebSocket服务器
   * @param {string} serverUrl - WebSocket服务器URL，如果未提供则使用配置中的URL
   * @param {Function} onConnected - 连接成功的回调函数
   * @param {Function} onError - 连接错误的回调函数
   */
  connect(serverUrl = WS_URL, onConnected, onError) {
    if (this.connected) {
      console.log('WebSocket is already connected');
      if (onConnected && typeof onConnected === 'function') {
        onConnected();
      }
      return;
    }

    // 清除之前的重连计时器
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer);
      this.reconnectTimer = null;
    }

    this.stompClient = new Client({
      webSocketFactory: () => new SockJS(serverUrl),
      debug: function (str) {
        if (process.env.NODE_ENV !== 'production') {
          console.log(str);
        }
      },
      reconnectDelay: WS_CONFIG.RECONNECT_INTERVAL,
      heartbeatIncoming: WS_CONFIG.PING_INTERVAL / 2,
      heartbeatOutgoing: WS_CONFIG.PING_INTERVAL / 2,
      onConnect: () => {
        this.connected = true;
        this.reconnectAttempts = 0;
        
        // 设置心跳来保持连接
        this.setupPing();
        
        // 重新订阅之前的所有订阅
        this.resubscribeAll();
        
        if (onConnected && typeof onConnected === 'function') {
          onConnected();
        }
        
        console.log('WebSocket connected successfully');
      },
      onStompError: (frame) => {
        console.error('STOMP protocol error:', frame);
        if (onError && typeof onError === 'function') {
          onError(frame);
        }
      },
      onWebSocketError: (event) => {
        console.error('WebSocket error:', event);
        this.connected = false;
        
        if (this.pingTimer) {
          clearInterval(this.pingTimer);
          this.pingTimer = null;
        }
        
        if (onError && typeof onError === 'function') {
          onError(event);
        }
        
        this.handleReconnect(serverUrl, onConnected, onError);
      },
      onWebSocketClose: () => {
        console.log('WebSocket connection closed');
        this.connected = false;
        
        if (this.pingTimer) {
          clearInterval(this.pingTimer);
          this.pingTimer = null;
        }
        
        this.handleReconnect(serverUrl, onConnected, onError);
      }
    });

    this.stompClient.activate();
  }

  /**
   * 处理重连逻辑
   * @private
   */
  handleReconnect(serverUrl, onConnected, onError) {
    if (this.reconnectAttempts < WS_CONFIG.MAX_RECONNECT_ATTEMPTS) {
      this.reconnectAttempts++;
      console.log(`Attempting to reconnect (${this.reconnectAttempts}/${WS_CONFIG.MAX_RECONNECT_ATTEMPTS})...`);
      
      this.reconnectTimer = setTimeout(() => {
        if (!this.connected) {
          this.connect(serverUrl, onConnected, onError);
        }
      }, WS_CONFIG.RECONNECT_INTERVAL);
    } else {
      console.error('Maximum reconnection attempts reached. Please try reconnecting manually.');
    }
  }

  /**
   * 设置心跳以保持连接
   * @private
   */
  setupPing() {
    if (this.pingTimer) {
      clearInterval(this.pingTimer);
    }
    
    this.pingTimer = setInterval(() => {
      if (this.connected && this.stompClient) {
        // 发送一个空的心跳消息
        this.stompClient.publish({ destination: '/app/ping', body: '' });
      } else {
        clearInterval(this.pingTimer);
        this.pingTimer = null;
      }
    }, WS_CONFIG.PING_INTERVAL);
  }

  /**
   * 重新订阅之前所有的订阅
   * @private
   */
  resubscribeAll() {
    if (!this.connected || !this.stompClient) return;
    
    const subscriptionsToRestore = new Map(this.subscriptions);
    this.subscriptions.clear();
    
    subscriptionsToRestore.forEach((value, destination) => {
      if (value.callback) {
        this.subscribe(destination, value.callback);
      }
    });
  }

  /**
   * 断开WebSocket连接
   */
  disconnect() {
    if (this.stompClient) {
      this.stompClient.deactivate();
      this.connected = false;
      this.subscriptions.clear();
      
      if (this.pingTimer) {
        clearInterval(this.pingTimer);
        this.pingTimer = null;
      }
      
      if (this.reconnectTimer) {
        clearTimeout(this.reconnectTimer);
        this.reconnectTimer = null;
      }
      
      console.log('WebSocket disconnected');
    }
  }

  /**
   * 订阅一个目标地址
   * @param {string} destination - 订阅的目标地址
   * @param {Function} callback - 接收消息的回调函数
   * @returns {Object} 订阅对象
   */
  subscribe(destination, callback) {
    if (!this.connected || !this.stompClient) {
      console.error('Cannot subscribe: WebSocket not connected');
      return null;
    }

    const subscription = this.stompClient.subscribe(destination, (message) => {
      if (callback && typeof callback === 'function') {
        try {
          const parsedMessage = JSON.parse(message.body);
          callback(parsedMessage);
        } catch (e) {
          callback(message.body);
        }
      }
    });

    this.subscriptions.set(destination, { subscription, callback });
    return subscription;
  }

  /**
   * 取消订阅一个目标地址
   * @param {string} destination - 要取消订阅的目标地址
   * @returns {boolean} 是否成功取消订阅
   */
  unsubscribe(destination) {
    if (this.subscriptions.has(destination)) {
      const { subscription } = this.subscriptions.get(destination);
      subscription.unsubscribe();
      this.subscriptions.delete(destination);
      return true;
    }
    return false;
  }

  /**
   * 发送消息到指定目标
   * @param {string} destination - 目标地址
   * @param {Object|string} message - 要发送的消息
   * @returns {boolean} 是否成功发送
   */
  send(destination, message) {
    if (!this.connected || !this.stompClient) {
      console.error('Cannot send message: WebSocket not connected');
      return false;
    }

    try {
      const messageStr = typeof message === 'string' ? message : JSON.stringify(message);
      this.stompClient.publish({
        destination: destination,
        body: messageStr
      });
      return true;
    } catch (error) {
      console.error('Error sending message:', error);
      return false;
    }
  }

  /**
   * 检查当前是否已连接
   * @returns {boolean} 连接状态
   */
  isConnected() {
    return this.connected;
  }
  
  /**
   * 获取指定的WebSocket主题
   * @param {string} topicKey - 主题的键名
   * @returns {string} 主题地址
   */
  getTopic(topicKey) {
    return WS_CONFIG.TOPICS[topicKey] || '';
  }
  
  /**
   * 获取指定的WebSocket目的地
   * @param {string} destKey - 目的地的键名
   * @returns {string} 目的地地址
   */
  getDestination(destKey) {
    return WS_CONFIG.DESTINATIONS[destKey] || '';
  }
}

// 创建单例
const wsService = new WebSocketService();

export default wsService; 